package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.constant.HttpStatus;
import com.zzyl.common.core.domain.entity.SysUser;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.framework.config.properties.HuaWeiIotConfigProperties;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IDeviceDataService;
import com.zzyl.nursing.service.IDeviceService;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.devicedata.IotMsgNotifyData;
import com.zzyl.nursing.vo.devicedata.IotMsgService;
import com.zzyl.nursing.vo.health.ProductVO;
import com.zzyl.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备信息Service业务层处理
 *
 * @author zzyl
 * @date 2025-10-23
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private IoTDAClient ioTDAClient;

    @Autowired
    private HuaWeiIotConfigProperties huaWeiIotConfigProperties;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private IDeviceDataService deviceDataService;


    /**
     * 查询设备信息
     *
     * @param id 设备信息主键
     * @return 设备信息
     */
    @Override
    public Device selectDeviceById(Long id) {
        return getById(id);
    }

    /**
     * 查询设备信息列表
     *
     * @param device 设备信息
     * @return 设备信息
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备信息
     *
     * @param device 设备信息
     * @return 结果
     */
    @Override
    public int insertDevice(Device device) {
        return save(device) ? 1 : 0;
    }

    /**
     * 修改设备信息
     *
     * @param deviceDto 设备信息
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateDevice(DeviceDto deviceDto) {

        // 修改数据库信息
        boolean flag = this.lambdaUpdate()
                .eq(Device::getId, deviceDto.getId())
                .set(StrUtil.isNotEmpty(deviceDto.getNickname()), Device::getNickname, deviceDto.getNickname())
                // .set(StrUtil.isNotEmpty(deviceDto.getDeviceDescription()), Device::getDeviceDescription, deviceDto.getDeviceDescription())
                .update();

        // 从表中查设备id
        Device device = this.lambdaQuery()
                .eq(Device::getId, deviceDto.getId())
                .one();
        if (ObjectUtil.isEmpty(device)) {
            throw new BaseException("数据库无该数据");
        }

        // 补充请求体
        UpdateDeviceRequest request = new UpdateDeviceRequest();
        request.setDeviceId(device.getIotId());

        // 修改数据
        UpdateDevice updateDevice = new UpdateDevice();
        //   updateDevice.setDeviceName(deviceDto.getDeviceName());
        updateDevice.setDescription(deviceDto.getNickname());
        //updateDevice.setExtensionInfo();
        //updateDevice.setAuthInfo();
        request.setBody(updateDevice);
        try {
            UpdateDeviceResponse updateDeviceResponse = ioTDAClient.updateDevice(request);
            // 判断返回数据
            if (updateDeviceResponse.getHttpStatusCode() != HttpStatus.SUCCESS) {
                throw new BaseException("获取云端返回错误");
            }


        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("获取云端错误");
        }
        return flag;
    }


    /**
     * 删除设备信息
     *
     * @param
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteDeviceById(String iotId, String productKey) {
        // 删除数据库
        boolean flag = this.remove(Wrappers.<Device>lambdaQuery()
                .eq(StrUtil.isNotEmpty(iotId), Device::getIotId, iotId)
                .eq(StrUtil.isNotEmpty(productKey), Device::getProductKey, productKey));

        // 删除云端数据
        DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
        deleteDeviceRequest.withDeviceId(iotId);

        try {
            DeleteDeviceResponse deleteDeviceResponse = ioTDAClient.deleteDevice(deleteDeviceRequest);

            // 判断返回
            if (deleteDeviceResponse.getHttpStatusCode() != HttpStatus.NO_CONTENT) {
                throw new BaseException("删除云端失败");
            }


        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("删除云端失败");
        }
        return flag;
    }

    /**
     * 从物联网平台同步产品列表
     */
    @Override
    public void syncProductList() {
        // 1.从华为云中获取
        try {
            ListProductsResponse listProductsResponse = ioTDAClient.listProducts(new ListProductsRequest());
            // 2.判断状态是否成功
            if (listProductsResponse.getHttpStatusCode() != HttpStatus.SUCCESS) {
                throw new BaseException("同步产品列表异常");
            }
            // 3.获取产品集合，转成JSON字符串
            List<ProductSummary> productSummaryList = listProductsResponse.getProducts();

            String productSummaryStr = JSONUtil.toJsonStr(productSummaryList);
            // 4.存于Redis缓存中
            redisTemplate.opsForValue().set(CacheConstants.IOT_PRODUCTSUMMARY_LIST, productSummaryStr);

        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("网络异常");
        }
    }

    /**
     * 查询所有产品列表
     *
     * @return
     */
    @Override
    public List<ProductVO> allProduct() {
        // 1.从缓存中获取
        String productSummaryStr = redisTemplate.opsForValue().get(CacheConstants.IOT_PRODUCTSUMMARY_LIST);
        // 2.如果为空返回空集合
        if (StringUtils.isBlank(productSummaryStr)) {
            return Collections.emptyList();
        }
        // 3.转成产品集合对象
        List<ProductSummary> productSummaryList = JSONUtil.toList(productSummaryStr, ProductSummary.class);

        // 3.格式转换为List<ProductVO>
        List<ProductVO> productVOList = productSummaryList.stream().map(productSummary ->
                ProductVO.builder()
                        .productKey(productSummary.getProductId())
                        .productName(productSummary.getName())
                        .build()).collect(Collectors.toList());
        return productVOList;
    }

    /**
     * 注册设备
     *
     * @param deviceDto
     * @return
     */
    @Override
    public boolean register(DeviceDto deviceDto) {
        // 1.判断设备名称是否重复
        Long countDeviceName = this.lambdaQuery()
                .eq(Device::getDeviceName, deviceDto.getDeviceName())
                .count();
        if (countDeviceName > 0) {
            throw new BaseException("名称已存在");
        }
        // 2.设备标识符是否相同
        // 借助雪花算法，生成唯一的标识符
        String nodeId = IdUtil.getSnowflakeNextIdStr();
        Long countNodeid = this.lambdaQuery().eq(Device::getNodeId, nodeId).count();
        if (countNodeid > 0) {
            throw new BaseException("设备标识符重复");
        }
        // 3.同一设备是否绑定了相同的产品
        Long countProduct = this.lambdaQuery()
                .eq(Device::getLocationType, deviceDto.getLocationType())
                .eq(Device::getBindingLocation, deviceDto.getBindingLocation())
                .eq(Device::getProductKey, deviceDto.getProductKey())
                .count();
        if (countProduct > 0) {
            throw new BaseException("同一位置不能重复绑定");
        }
        // 4.注册设备

        AddDeviceRequest addDeviceRequest = new AddDeviceRequest();


        // 请求体增加参数
        AddDevice addDevice = new AddDevice();
        addDevice.setNodeId(nodeId);
        addDevice.setDeviceName(deviceDto.getDeviceName());
        addDevice.setDescription(deviceDto.getNickname());
        addDevice.setProductId(deviceDto.getProductKey()); // 产品的key

        // 设置秘钥
        String secret = IdUtil.fastSimpleUUID();

        AuthInfo authInfo = new AuthInfo();
        authInfo.setSecret(secret);
        // 秘钥是嵌套在authInfo里面的
        addDevice.setAuthInfo(authInfo);
        // 设置请求体
        addDeviceRequest.setBody(addDevice);


        try {
            // 长传IOT云端
            AddDeviceResponse addDeviceResponse = ioTDAClient.addDevice(addDeviceRequest);

            // 判断返回数据状态
            if (addDeviceResponse.getHttpStatusCode() != HttpStatus.CREATED) {
                throw new BaseException("IOT平台新增失败");
            }

            // 云生成规则为"product_id"+"_"+"node_id"拼接
            String iotId = addDeviceResponse.getDeviceId();
            // 5.保存到设备表
            Device device = BeanUtil.toBean(deviceDto, Device.class);
            device.setIotId(iotId);
            device.setNodeId(nodeId);
            device.setSecret(secret);
            device.setHaveEntranceGuard(deviceDto.getNickname().contains("门禁") ? 1 : 0);

            // 从缓存中获取产品名字
            String productKey = deviceDto.getProductKey();
            String productName = getProductNameByCache(productKey);


            if (StrUtil.isNotBlank(productName)) {
                device.setProductName(productName);
            }

            return this.save(device);

        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("获取云端错误");
        }
    }

    /**
     * 从缓存中获取产品名字
     *
     * @param productKey
     * @return
     */
    private String getProductNameByCache(String productKey) {
        String jsonStr = redisTemplate.opsForValue().get(CacheConstants.IOT_PRODUCTSUMMARY_LIST);

        if (StrUtil.isBlank(jsonStr)) {
            return null;
        }

        // 转成产品集合
        List<ProductSummary> productSummaryList = JSONUtil.toList(jsonStr, ProductSummary.class);
        ProductSummary summary = productSummaryList.stream().filter(productSummary -> productKey.equals(productSummary.getProductId())).findFirst().get();

        if (ObjectUtil.isNotEmpty(summary)) {
            return summary.getName();
        }

        return null;

    }

    /**
     * 查询设备详细数据
     *
     * @param iotId
     * @param productKey
     * @return
     */
    @Override
    public DeviceDetailVo queryDeviceDetail(String iotId, String productKey) {
        // 从数据库中查询
        Device device = this.lambdaQuery()
                .eq(Device::getIotId, iotId)
                .one();

        // 判断是否为空
        if (ObjectUtil.isEmpty(device)) {
            throw new BaseException("查询数据失败");
        }

        // 拼接数据
        DeviceDetailVo deviceDetailVo = BeanUtil.toBean(device, DeviceDetailVo.class);
        deviceDetailVo.setGmtCreate(device.getCreateTime());


        // 拼接数据库信息
        SysUser sysUser = sysUserService.selectUserById(Long.valueOf(device.getCreateBy()));

        if (ObjectUtil.isNotEmpty(sysUser)) {
            deviceDetailVo.setCreator(sysUser.getUserName());
        }
        deviceDetailVo.setDeviceSecret(device.getSecret());
        // 配置中读取
        deviceDetailVo.setRegion(huaWeiIotConfigProperties.getRegionId());

        // 从IOT云端查询
        ShowDeviceRequest showDeviceRequest = new ShowDeviceRequest();
        showDeviceRequest.withDeviceId(iotId);

        try {
            ShowDeviceResponse showDeviceResponse = ioTDAClient.showDevice(showDeviceRequest);

            if (showDeviceResponse.getHttpStatusCode() != HttpStatus.SUCCESS) {
                throw new BaseException("获取云端错误");
            }

            // 拷贝云端返回数据给VO
            BeanUtil.copyProperties(showDeviceResponse, deviceDetailVo);

            String activeTime = showDeviceResponse.getActiveTime();
            // 判断激活时间
            if (ObjectUtil.isNotEmpty(activeTime)) {
                // 时间格式化
                LocalDateTime gmtActive = OffsetDateTime.parse(activeTime)
                        .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                        .toLocalDateTime();

                deviceDetailVo.setGmtActive(gmtActive);
            }
            deviceDetailVo.setDeviceStatus(showDeviceResponse.getStatus());

            // 判断固件版本
            if (ObjectUtil.isNotEmpty(showDeviceResponse.getFwVersion())) {
                deviceDetailVo.setFirmwareVersion(showDeviceResponse.getFwVersion());
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("获取云端错误");
        }

        return deviceDetailVo;
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param productKey
     * @return
     */
    @Override
    public JSONObject queryProductModelInfo(String productKey) {

        // 补充请求体
        ShowProductRequest showProductRequest = new ShowProductRequest();
        showProductRequest.setProductId(productKey);

        try {
            // 从IOT云端查模型
            ShowProductResponse showProductResponse = ioTDAClient.showProduct(showProductRequest);

            // 判断请求是否成功
            if (showProductResponse.getHttpStatusCode() != HttpStatus.SUCCESS) {
                throw new BaseException("查询数据错误");
            }

            List<ServiceCapability> serviceCapabilities = showProductResponse.getServiceCapabilities();

            JSONObject jsonObject = null;
            if (CollUtil.isNotEmpty(serviceCapabilities)) {
                // 转成Json字符串对象,hutool支持下划线转驼峰
                jsonObject = JSONUtil.parseObj(serviceCapabilities.get(0));

            }

            return jsonObject;

        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("查询云端数据失败");
        }
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param deviceName
     * @param productKey
     * @return
     */
    @Override
    public Map<String, Object> queryDevicePropertyStatus(String deviceName, String productKey) {

        Device device = this.lambdaQuery()
                .eq(Device::getDeviceName, deviceName)
                .eq(Device::getProductKey, productKey)
                .one();

        if (ObjectUtil.isEmpty(device)) {
            throw new BaseException("表中无数据");
        }

        // 补充请求体
        ShowDeviceShadowRequest showDeviceShadowRequest = new ShowDeviceShadowRequest();
        showDeviceShadowRequest.setDeviceId(device.getIotId());

        try {
            ShowDeviceShadowResponse showDeviceShadowResponse = ioTDAClient.showDeviceShadow(showDeviceShadowRequest);

            // 判断返回值是否正确
            if (showDeviceShadowResponse.getHttpStatusCode() != HttpStatus.SUCCESS) {
                throw new BaseException("云端获取错误");
            }

            List<DeviceShadowData> shadow = showDeviceShadowResponse.getShadow();
            if (CollUtil.isEmpty(shadow)) {
                return Collections.emptyMap();
            }

            // 时间格式化
            String eventTime = shadow.get(0).getReported().getEventTime();
            if (StrUtil.isNotBlank(eventTime)) {
                LocalDateTime time = OffsetDateTime
                        .parse(eventTime, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX"))
                        .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                        .toLocalDateTime();


                List<Map<String, Object>> propertyStatusInfoList = new ArrayList<>();

                JSONObject jsonObject = JSONUtil.parseObj(shadow.get(0).getReported().getProperties());

                jsonObject.forEach((k, v) -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("identifier", k);
                    map.put("value", v);
                    map.put("time", time);
                    propertyStatusInfoList.add(map);
                });

                // 准备返回结果容器

                HashMap<String, Object> propertyStatusInfoMap = new HashMap<>();
                propertyStatusInfoMap.put("propertyStatusInfo", propertyStatusInfoList);

                HashMap<String, Object> listMap = new HashMap<>();
                listMap.put("list", propertyStatusInfoMap);

                return listMap;
            }


        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("云端获取错误");
        }
        return null;
    }

    /**
     * 基于IOT设备上传通知的数据，批量保存设备数据
     *
     * @param iotMsgNotifyData
     */
    @Override
    public void saveBatchData(IotMsgNotifyData iotMsgNotifyData) {
        // 1.判断表中是否有这个设备
        String iotId = iotMsgNotifyData.getHeader().getDeviceId();
        Device device = this.lambdaQuery().eq(Device::getIotId, iotId).one();

        if (ObjectUtil.isEmpty(device)) {
            throw new BaseException("查不到该设备");
        }

        // 2.解析数据
        List<IotMsgService> serviceList = iotMsgNotifyData.getBody().getServices();

        serviceList.forEach(service -> {
            // 获取属性值和上报时间
            Map<String, Object> properties = service.getProperties();
            String eventTime = service.getEventTime();
            // 时间解析
            LocalDateTime alarmTime = OffsetDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX"))
                    .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime();
            // 判断属性值
            if (CollUtil.isEmpty(properties)) {
                throw new BaseException("获取属性失败");
            }
            // 3.构造批量存入对象
            List<DeviceData> deviceDataList = new ArrayList<>();

            properties.forEach((k, v) -> {
                String functionId = k;
                String dataValue = v.toString();

                DeviceData deviceData = DeviceData.builder()
                        .deviceName(device.getDeviceName())
                        .iotId(iotId)
                        .nodeId(device.getNodeId())
                        .nickname(device.getNickname())
                        .productKey(device.getProductKey())
                        .productName(device.getProductName())
                        .functionId(functionId)
                        .accessLocation(device.getBindingLocation())
                        .locationType(device.getLocationType())
                        .physicalLocationType(device.getPhysicalLocationType())
                        .deviceDescription(device.getDeviceDescription())
                        .dataValue(dataValue)
                        .alarmTime(alarmTime)
                        .build();

                deviceDataList.add(deviceData);
            });

            // 批量保存数据库
            deviceDataService.saveBatch(deviceDataList);
            // 把最新数据放入缓存中
            redisTemplate.opsForHash().put(CacheConstants.IOT_DEVICE_LAST_DATA, iotId, JSONUtil.toJsonStr(deviceDataList));
        });




    }
}
